package vip.manda.framework.data;

import cn.hutool.db.Db;
import vip.manda.framework.bean.BeanContainer;
import vip.manda.framework.bean.BeanFactory;
import vip.manda.framework.core.Configs;
import vip.manda.framework.core.Function;
import vip.manda.framework.data.repository.impl.BaseRepositoryImpl;
import vip.manda.framework.log.Log;
import vip.manda.framework.log.LogFactory;

import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author hongda.li 2022-04-12 16:15
 * 自动建表机制会默认创建ID主键与用于实现乐观锁的版本号字段
 */
@Function(order = Function.Common.DATA_FUNCTION)
public class DataFunction implements Function.FunctionMethod {
    private static final Log log = LogFactory.getLog();
    private static final String EXISTS = "select count(*) from sqlite_master where name=?";
    private static final Map<String, BaseRepositoryImpl> REPOSITORY_CACHE = new HashMap<>();

    public DataFunction() {
        log.func("execute function[{}]", DataFunction.class.getName());
    }

    public static Map<String, BaseRepositoryImpl> getRepositoryCache(){
        return REPOSITORY_CACHE;
    }
    @Override
    public void doFunction(Set<Class<?>> classes) {
        Configs.setDefaultConfig(Configs.DataBase.PATH, Configs.DataBase.Value.PATH);
        Configs.setDefaultConfig(Configs.DataBase.NAME, Configs.DataBase.Value.NAME);
        List<BaseRepositoryImpl> repositories = new ArrayList<>();
        BeanContainer container = BeanFactory.getContainer();
        classes.stream()
                .filter(BaseRepositoryImpl.class::isAssignableFrom)
                .filter(clazz -> clazz != BaseRepositoryImpl.class)
                .filter(container::exists)
                .collect(Collectors.toList())
                .forEach(repository -> repositories.add((BaseRepositoryImpl) container.getBean(repository)));
        repositories.forEach(repository -> {
            log.info("Capture a repository[{}]", repository.getClass().getName());
            REPOSITORY_CACHE.put(repository.getClass().getSimpleName(), repository);
            try {
                boolean exists = checkTableExists(repository.getTableName());
                if (!exists){
                    createTable(repository.getTableName(), repository.getColumns());
                }
            } catch (SQLException e) {
                log.error("Repository auto create table failed[{}]", repository.getTableName());
               e.printStackTrace();
            }
        });
    }

    private boolean checkTableExists(String tableName) throws SQLException {
        Number number = Db.use(DataBaseSource.getDataSource()).queryNumber(EXISTS, tableName);
        return number != null && number.intValue() != 0;
    }

    private void createTable(String tableName, Map<String, DataType> columns) throws SQLException {
        StringBuilder builder = new StringBuilder();
        builder.append("CREATE TABLE ").append(tableName).append(" (`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,");
        columns.forEach((key, value) -> builder.append("`").append(key).append("`").append(" ").append(value.getType())
                .append("  DEFAULT NULL,"));
        builder.append("`version` INTEGER DEFAULT NULL);");
        Db.use(DataBaseSource.getDataSource()).execute(builder.toString());
        log.info("Repository auto create table success[{}]", builder.toString());
    }
}
